import streamlit as st
import requests
import json
from requests.exceptions import RequestException
import time

st.set_page_config(
    page_title="API测试工具",
    page_icon="🧪",
    layout="wide"
)

# 页面标题
st.title("API测试工具 🧪")
st.markdown("使用这个工具来测试和调试API请求")

# 初始化会话状态
if 'headers' not in st.session_state:
    st.session_state.headers = [{"key": "Content-Type", "value": "application/json"}]

if 'form_data' not in st.session_state:
    st.session_state.form_data = [{"key": "", "value": ""}]

if 'query_params' not in st.session_state:
    st.session_state.query_params = [{"key": "", "value": ""}]

# 创建两列布局
col1, col2 = st.columns([1, 1])

with col1:
    st.subheader("请求配置")
    
    # API URL输入
    url = st.text_input("API URL", "https://jsonplaceholder.typicode.com/posts")
    
    # HTTP方法选择
    http_method = st.selectbox(
        "HTTP方法",
        ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]
    )
    
    # 请求头配置
    st.subheader("请求头")
    headers_container = st.container()
    
    # 显示当前的请求头
    with headers_container:
        for i, header in enumerate(st.session_state.headers):
            cols = st.columns([3, 3, 1])
            with cols[0]:
                key = st.text_input(f"键 #{i+1}", header["key"], key=f"header_key_{i}")
                st.session_state.headers[i]["key"] = key
            with cols[1]:
                value = st.text_input(f"值 #{i+1}", header["value"], key=f"header_value_{i}")
                st.session_state.headers[i]["value"] = value
            with cols[2]:
                if st.button("删除", key=f"delete_header_{i}"):
                    st.session_state.headers.pop(i)
                    st.rerun()
    
    # 添加新的请求头
    if st.button("添加请求头"):
        st.session_state.headers.append({"key": "", "value": ""})
        st.rerun()
    
    # 请求体配置（仅对POST, PUT, PATCH有效）
    if http_method in ["POST", "PUT", "PATCH"]:
        st.subheader("请求体")
        body_type = st.radio("请求体类型", ["JSON", "表单数据", "原始文本"])
        
        if body_type == "JSON":
            request_body = st.text_area(
                "JSON请求体",
                '{\n  "title": "foo",\n  "body": "bar",\n  "userId": 1\n}',
                height=200
            )
        elif body_type == "表单数据":
            # 显示表单数据输入
            for i, field in enumerate(st.session_state.form_data):
                cols = st.columns([3, 3, 1])
                with cols[0]:
                    key = st.text_input(f"表单键 #{i+1}", field["key"], key=f"form_key_{i}")
                    st.session_state.form_data[i]["key"] = key
                with cols[1]:
                    value = st.text_input(f"表单值 #{i+1}", field["value"], key=f"form_value_{i}")
                    st.session_state.form_data[i]["value"] = value
                with cols[2]:
                    if st.button("删除", key=f"delete_form_{i}"):
                        st.session_state.form_data.pop(i)
                        st.rerun()
            
            if st.button("添加表单字段"):
                st.session_state.form_data.append({"key": "", "value": ""})
                st.rerun()
            
            # 构建表单数据字典
            request_body = {item["key"]: item["value"] for item in st.session_state.form_data if item["key"]}
        else:  # 原始文本
            request_body = st.text_area("原始请求体", "", height=200)
    
    # 查询参数
    st.subheader("查询参数")
    
    # 显示查询参数输入
    for i, param in enumerate(st.session_state.query_params):
        cols = st.columns([3, 3, 1])
        with cols[0]:
            key = st.text_input(f"参数名 #{i+1}", param["key"], key=f"param_key_{i}")
            st.session_state.query_params[i]["key"] = key
        with cols[1]:
            value = st.text_input(f"参数值 #{i+1}", param["value"], key=f"param_value_{i}")
            st.session_state.query_params[i]["value"] = value
        with cols[2]:
            if st.button("删除", key=f"delete_param_{i}"):
                st.session_state.query_params.pop(i)
                st.rerun()
    
    if st.button("添加查询参数"):
        st.session_state.query_params.append({"key": "", "value": ""})
        st.rerun()
    
    # 超时设置
    timeout = st.number_input("请求超时（秒）", min_value=1, max_value=60, value=10)
    
    # 发送请求按钮
    send_button = st.button("发送请求", type="primary")

# 右侧显示响应
with col2:
    st.subheader("响应结果")
    
    # 创建响应区域的占位符
    response_placeholder = st.empty()
    
    if send_button:
        # 构建请求头字典
        headers_dict = {h["key"]: h["value"] for h in st.session_state.headers if h["key"]}
        
        # 构建查询参数字典
        params_dict = {p["key"]: p["value"] for p in st.session_state.query_params if p["key"]}
        
        # 准备请求体
        if http_method in ["POST", "PUT", "PATCH"]:
            if body_type == "JSON":
                try:
                    # 尝试解析JSON
                    data = json.loads(request_body)
                except json.JSONDecodeError:
                    st.error("JSON格式错误，请检查请求体")
                    data = request_body
            elif body_type == "表单数据":
                data = request_body
            else:  # 原始文本
                data = request_body
        else:
            data = None
        
        # 显示加载状态
        with response_placeholder.container():
            with st.spinner("发送请求中..."):
                start_time = time.time()
                try:
                    # 发送请求
                    response = requests.request(
                        method=http_method,
                        url=url,
                        headers=headers_dict,
                        params=params_dict,
                        data=data if http_method in ["POST", "PUT", "PATCH"] and body_type != "JSON" else None,
                        json=data if http_method in ["POST", "PUT", "PATCH"] and body_type == "JSON" else None,
                        timeout=timeout
                    )
                    
                    # 计算响应时间
                    response_time = time.time() - start_time
                    
                    # 显示响应状态
                    status_color = "green" if response.status_code < 400 else "red"
                    st.markdown(f"### 状态码: <span style='color:{status_color}'>{response.status_code}</span>", unsafe_allow_html=True)
                    st.markdown(f"**响应时间**: {response_time:.2f} 秒")
                    
                    # 显示响应头
                    with st.expander("响应头"):
                        for key, value in response.headers.items():
                            st.text(f"{key}: {value}")
                    
                    # 显示响应体
                    st.subheader("响应体")
                    
                    # 尝试解析为JSON
                    try:
                        json_response = response.json()
                        st.json(json_response)
                        
                        # 提供下载响应的选项
                        json_str = json.dumps(json_response, indent=2)
                        st.download_button(
                            label="下载响应 (JSON)",
                            data=json_str,
                            file_name="response.json",
                            mime="application/json"
                        )
                    except ValueError:
                        # 如果不是JSON，显示为文本
                        st.text_area("响应内容", response.text, height=400)
                        
                        # 提供下载响应的选项
                        st.download_button(
                            label="下载响应 (文本)",
                            data=response.text,
                            file_name="response.txt",
                            mime="text/plain"
                        )
                
                except RequestException as e:
                    st.error(f"请求错误: {str(e)}")
                except Exception as e:
                    st.error(f"发生错误: {str(e)}")

# 添加使用说明
with st.expander("使用说明"):
    st.markdown("""
    ### 如何使用这个API测试工具
    
    1. **输入API URL**: 输入你想要测试的API的完整URL
    2. **选择HTTP方法**: 从下拉菜单中选择适当的HTTP方法（GET, POST等）
    3. **配置请求头**: 添加所需的HTTP请求头
    4. **添加请求体** (仅POST/PUT/PATCH): 根据需要选择JSON、表单数据或原始文本格式
    5. **添加查询参数**: 如果需要，添加URL查询参数
    6. **设置超时**: 设置请求超时时间
    7. **发送请求**: 点击"发送请求"按钮
    8. **查看结果**: 在右侧面板查看响应状态、头信息和响应体
    
    你可以下载响应内容以便进一步分析。
    """)

# 页脚
st.markdown("---")
st.markdown("API测试工具 | 用于测试和调试HTTP API请求")